package app;

import ch.swingfx.twinkle.NotificationBuilder;
import ch.swingfx.twinkle.style.INotificationStyle;
import ch.swingfx.twinkle.style.theme.DarkDefaultNotification;
import ch.swingfx.twinkle.window.Positions;
import entities.Department;
import entities.Roll;
import entities.TimeSlot;
import java.awt.Frame;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author yoshi
 */
public class Global {

    public static Connection getConnection() {
        Connection connection = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost/remedy_scheduler", "root", "imissuak");
        } catch (SQLException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            return connection;
        }
    }
    private static SimpleDateFormat defaultHmDateFormat = new SimpleDateFormat("HH:mm");
    private static SimpleDateFormat defaultDateFormat = new SimpleDateFormat("MMM dd, yyyy");
    private static String scheduleQuery = "SELECT"
            + " e.roll_id, r.name AS roll_name, r.head AS roll_head,"
            + " e.username, e.first_name, e.last_name, s.employee_id, e.gender,"
            + " s.time_slot_id, ts.from, ts.to,"
            + " s.id, s.date, s.status"
            + " FROM employees AS e"
            + " JOIN employee_schedules AS s ON e.id = s.employee_id"
            + " JOIN time_slots AS ts ON ts.id = s.time_slot_id"
            + " JOIN rolls AS r ON e.roll_id = r.id";
    private static String requestQuery = "SELECT"
            // "request"
            + " esr.id, esr.from_schedule_id, esr.request_date, esr.time_slot_id AS request_time_slot, esr.note AS request_note, esr.status AS request_status, "
            + " esr.time_slot_id AS request_time_slot_id, rts.from AS request_from, rts.to AS request_to, "
            // "from" branch
            + " sf.id AS sf_id, sf.date AS sf_date, sf.status AS sf_status, "
            + " tsf.id AS tsf_id, tsf.from AS tsf_from, tsf.to AS tsf_to, "
            + " ef.id AS ef_id, ef.username AS ef_username, ef.first_name AS ef_first_name, ef.last_name AS ef_last_name, ef.gender AS ef_gender, "
            + " rf.id AS rf_id, rf.name AS rf_name, rf.head AS rf_head, "
            // "to" branch
            + " et.id AS et_id, et.username AS et_username, et.first_name AS et_first_name, et.last_name AS et_last_name, et.gender AS et_gender, "
            + " rt.id AS rt_id, rt.name AS rt_name, rt.head AS rt_head "
            // "request"
            + " FROM employee_shift_requests AS esr "
            + " LEFT JOIN time_slots AS rts ON esr.time_slot_id = rts.id"
            // "from" branch
            + " LEFT JOIN employee_schedules AS sf ON esr.from_schedule_id = sf.id "
            + " LEFT JOIN time_slots AS tsf ON sf.time_slot_id = tsf.id "
            + " LEFT JOIN employees AS ef ON sf.employee_id = ef.id "
            + " LEFT JOIN rolls AS rf ON ef.roll_id = rf.id "
            // "to" branch
            + " LEFT JOIN employees AS et ON esr.employee_id = et.id "
            + " LEFT JOIN rolls AS rt ON et.roll_id = rt.id ";
    private static String employeeQuery = "SELECT"
            + " * FROM employees AS e JOIN rolls AS r ON e.roll_id = r.id";
    private static String timeSlotQuery = "SELECT * FROM time_slots";
    private static String holidayQuery = "SELECT * FROM holidays";

    public static SimpleDateFormat getDefaultDateFormat() {
        return defaultDateFormat;
    }

    public static SimpleDateFormat getDefaultHmDateFormat() {
        return defaultHmDateFormat;
    }

    public static String getRequestQuery() {
        return requestQuery;
    }

    public static String getScheduleQuery() {
        return scheduleQuery;
    }

    public static String getEmployeeQuery() {
        return employeeQuery;
    }

    public static String getTimeSlotQuery() {
        return timeSlotQuery;
    }

    public static String getHolidayQuery() {
        return holidayQuery;
    }
    
    
    private static Auth auth = null;

    public static void setAuth(Auth auth) {
        Global.auth = auth;
    }

    public static Auth getAuth() {
        return auth;
    }
    private static Frame frame;
    
    public static void setFrame(Frame frame){
        Global.frame = frame;
    }

    public static Frame getFrame() {
        return frame;
    }
    private static HashMap<Long, Department> departments = new HashMap<Long, Department>();
    private static HashMap<Long, TimeSlot> timeSlots = new HashMap<Long, TimeSlot>();
    private static HashMap<Long, Roll> rolls = new HashMap<Long, Roll>();

    public static HashMap<Long, Department> getDepartments() {
        if (departments != null) {
            return departments;
        } else {
            Connection connection = Global.getConnection();
            Global.loadDepartments(connection);
            try {
                connection.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                return departments;
            }
        }
    }

    public static HashMap<Long, TimeSlot> getTimeSlots() {
        if (timeSlots != null) {
            return timeSlots;
        } else {
            Connection connection = Global.getConnection();
            Global.loadTimeSlots(connection);
            try {
                connection.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                return timeSlots;
            }
        }
    }

    public static HashMap<Long, Roll> getRolls() {
        if (rolls != null) {
            return rolls;
        } else {
            Connection connection = Global.getConnection();
            Global.loadRolls(connection);
            try {
                connection.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                return rolls;
            }
        }
    }

    public static synchronized void loadDepartments(Connection connection) {
        departments.clear();
        Statement st = null;
        ResultSet rs = null;
        try {
            st = connection.createStatement();
            rs = st.executeQuery("SELECT * FROM departments WHERE active = 1");

            while (rs.next()) {
                departments.put(rs.getLong("id"), new Department(rs));
            }
        } catch (SQLException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                rs.close();
                st.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static synchronized void loadTimeSlots(Connection connection) {
        timeSlots.clear();
        Statement st = null;
        ResultSet rs = null;
        try {
            st = connection.createStatement();
            rs = st.executeQuery("SELECT * FROM time_slots");

            while (rs.next()) {
                timeSlots.put(rs.getLong("id"), new TimeSlot(rs));
            }
        } catch (SQLException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                rs.close();
                st.close();
                connection.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static synchronized void loadRolls(Connection connection) {
        rolls.clear();
        Statement st = null;
        ResultSet rs = null;
        try {
            st = connection.createStatement();
            rs = st.executeQuery("SELECT * FROM rolls");

            while (rs.next()) {
                rolls.put(rs.getLong("id"), new Roll(rs));
            }
        } catch (SQLException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                rs.close();
                st.close();
            } catch (SQLException ex) {
                Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    private static String hashSecretKey = "cc368d4ee638ed263ab0d14221c26e86";

    public static String hashPassword(String password) {
        String hashText = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());
            BigInteger bigInt = new BigInteger(1, md.digest());
            String md5HashedText = bigInt.toString(16);

            MessageDigest sha = MessageDigest.getInstance("SHA1");
            sha.update((md5HashedText + hashSecretKey).getBytes());
            bigInt = new BigInteger(1, sha.digest());
            hashText = bigInt.toString(16);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Global.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            return hashText;
        }
    }

    public static void notify(String title, String message, int type) {
        // AA the text
        System.setProperty("swing.aatext", "true");

        // First we define the style/theme of the window.
        // Note how we override the default values
        INotificationStyle style = new DarkDefaultNotification().withWidth(400) // Optional
                .withAlpha(0.9f) // Optional
                ;

        // Now lets build the notification
        new NotificationBuilder().withStyle(style) // Required. here we set the previously set style
                .withTitle(title) // Required.
                .withMessage(message) // Optional
                //.withIcon(new ImageIcon(QuickStart.class.getResource("/twinkle.png"))) // Optional. You could also use a String path
                .withDisplayTime(10000) // Optional
                .withPosition(Positions.NORTH_EAST) // Optional. Show it at the center of the screen
                .showNotification(); // this returns a UUID that you can use to identify events on the listener
    }
}
